package org.iabako.server.serviceimpl.business;

import org.apache.commons.lang3.time.DateUtils;
import org.iabako.server.dao.JpaDAO;
import org.iabako.server.dao.business.InstallmentDAO;
import org.iabako.server.dao.business.QueryDefinitionDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.business.Installment;
import org.iabako.shared.entity.business.Sale;
import org.iabako.shared.entity.enumeration.InstallmentStatus;
import org.iabako.shared.entity.enumeration.TrackingType;
import org.iabako.shared.iservice.business.InstallmentService;
import org.iabako.shared.iservice.business.SaleService;
import org.iabako.shared.iservice.business.TrackingService;
import org.iabako.shared.iservice.user.UserService;
import org.iabako.shared.querydefinition.SearchMotorQueryEnum;
import org.iabako.shared.querydefinition.columndefinition.ColumnDefinition;
import org.iabako.shared.querydefinition.columndefinition.InstallmentColumnEnum;
import org.iabako.shared.querydefinition.dto.IconValue;
import org.iabako.shared.querydefinition.dto.QueryDefinitionDTO;
import org.iabako.shared.querydefinition.dto.QueryResultDTO;
import org.iabako.shared.querydefinition.dto.QueryResultValue;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * Created by jose on 02/09/14.
 */

@org.springframework.stereotype.Service("installmentService")
public class InstallmentServiceImpl extends AbstractServiceImpl implements InstallmentService {


    @Autowired
    private InstallmentDAO installmentDAO;
    @Autowired
    private SaleService saleService;
    @Autowired
    private UserService userService;
    @Autowired
    private QueryDefinitionDAO queryDefinitionDAO;
    @Autowired
    private TrackingService trackingService;

    @Override
    protected JpaDAO getDAO() {
        return installmentDAO;
    }

    public QueryDefinitionDTO getSearchQueryDefinitionDTO(QueryDefinitionDTO qd) {
        qd.setSearchMotorQuery(SearchMotorQueryEnum.InstallmentSearch);
        queryDefinitionDAO.executeQueryDefinition(qd);

        qd.getColumnsExclusion().add(InstallmentColumnEnum.paymentRequestBefore);

        qd.setCustomModifications(true);

        for (QueryResultDTO result : qd.getResults().values()) {

            boolean paymentRequestBefore = false;
            boolean paymentRequestAfter = false;
            //Linked ordered map :
            for (ColumnDefinition columnDefinition : result.getValues().keySet()) {
                if (columnDefinition == InstallmentColumnEnum.paymentRequestBefore) {
                    paymentRequestBefore = "true".equals(result.getValues().get(columnDefinition).getValue());
                }

                if (columnDefinition == InstallmentColumnEnum.paymentRequestAfter) {
                    IconValue paymentRequestIcon = ((IconValue) result.getValues().get(columnDefinition).getValue());
                    paymentRequestAfter = "true".equals(paymentRequestIcon.getText());

                    if (paymentRequestBefore && paymentRequestAfter) {
                        paymentRequestIcon.setText(messages.getLabel("installment_payment_request_before_and_after"));
                    } else if (paymentRequestBefore) {
                        paymentRequestIcon.setText(messages.getLabel("installment_payment_request_before"));
                    } else if (paymentRequestAfter) {
                        paymentRequestIcon.setText(messages.getLabel("installment_payment_request_after"));
                    } else {
                        paymentRequestIcon.setText(null);
                    }
                }
            }

            QueryResultValue qrValue = new QueryResultValue();

            Date installmentDate = (Date) (result.getValues().get(InstallmentColumnEnum.date)).getValue();

            if (installmentDate.compareTo(DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)) > 0) {
                qrValue.setValue(InstallmentStatus.future);
            } else {
                qrValue.setValue(InstallmentStatus.past);
            }

            result.getValues().put(InstallmentColumnEnum.status, qrValue);
        }

        return qd;
    }

    public QueryDefinitionDTO setSearchCriteriaFromSuggest(QueryDefinitionDTO qd, Long hiddenSelectionCode, String value) {
        return null;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Installment save(Installment installment, boolean noTrack) {

        installment.setDate(GenericTools.getDateFromString(installment.getDateString()));

        boolean isCreation = installment.getId() == null;

        Sale sale = (Sale) saleService.getById(installment.getSale().getId());
        if (isCreation) {
            sale.getInstallments().add(installment);
        }
        if (!noTrack) {
            trackingService.addTrackingToUserSession(isCreation ? TrackingType.installmentNew : TrackingType.installmentModify, sale);
        }

        installment.setAmount(ServerTools.round(installment.getAmount()));
        //Persist or merge installment (Id will be used in async call return)
        installment = (Installment) super.save(installment);

        sale.setRecalculatedTotal(sale.calculateAmountFromPaymentsAndInstalments());
        setBusinessTrackInfo(sale);

        if (sale.getClient() != null) {
            //Client must be enabled if he has future or pending installments
            sale.getClient().setDisabled(false);
        }

        saleService.calculateStatusAndSave(sale, false);

        return installment;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Installment save(Installment installment) {
        return save(installment, false);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean remove(Installment installment, boolean noTrack) {
        Sale sale = installment.getSale();
        sale.getInstallments().remove(installment);

        sale.setRecalculatedTotal(sale.calculateAmountFromPaymentsAndInstalments());
        setBusinessTrackInfo(sale);

        saleService.calculateStatusAndSave(sale, false);

        if (!noTrack) {
            trackingService.addTrackingToUserSession(TrackingType.installmentDelete, sale);
        }

        return super.remove(installment);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean remove(AbstractEntity abstractEntity) {
        return remove((Installment) abstractEntity, false);
    }

    public List<Installment> getBySale(Sale entity) {
        return installmentDAO.findBySale(entity);
    }
}
